// Game.h
//
// Created By: Jeremy Butler
// Created On: 23-Mar-2011
//
// A Facade class to model a Chess Board.

#ifndef GAME_H
#define GAME_H

#include "Piece.h"
#include "Move.h"
#include "Board.h"

#include <vector>
#include <deque>
using namespace std;

class Game {
private:
  Board board;
  Location selectedSpace;
  set<Location> selectedSpaceMoves;
  deque<Move> moveHistory;
  bool b_blackInCheck;
  bool b_whiteInCheck;
  bool b_blackInCheckMate;
  bool b_whiteInCheckMate;
  bool b_staleMate;

public:
  //! @brief No-Arg Constructor
  Game();

  //! @brief Copy Constructor
  //! @param other The other chess model to copy.
  Game(const Game & other);

  //! @brief Constructor
  //! @param pieces The Pieces that are to be initialized onto the board
  //! @param history The Moves that are to be initialized into the Move History
  Game(const vector<pair<Piece *, Location> > & pieces, const deque<Move> & history);

  //! @brief Operator = used to copy another Game into this one
  //! @param other the Game to be copied to this one
  //! @return a reference to the newly copied Game game
  Game & operator = (const Game & other);

  //! @brief Destructor
  ~Game();

  const Piece * operator() (int row, int col) const;

  //! @brief Move the currently selected piece on the board.
  //! @param row The row of the Space that the Piece is to move to.
  //! @param col The column of the Space that the Piece is to move to.
  //! @param newPiece The type that the piece is after the move.
  //! 	(usually only used for Pawn promotion)
  //! @return a pointer to the successful Move or NULL if no Move was made.
  //!
  //! If the Space specified by row and col are not in the valid moves of the currently
  //! selected piece, or if no Piece is currently selected, then nothing happens.
  const Move * MovePiece(int row, int col, PieceType newPieceType = NO_TYPE);

  //! @brief Set which Space is selected.
  //! @param row the row of the Space that is to be selected.
  //! @param col the column of the Space that is to be selected.
  void SetSelectedSpace(int row, int col);

  //! @brief Get the currently selected space.
  //! @return a pointer to the location of the currently selected Space.
  const Location & GetSelectedSpace() const;

  //! @brief Get the valid Moves of a piece in the game.
  //! @return a set of Locations of the valid moves of the piece at (row, col), or
  //! 	an empty set if no piece exists at (row, col).
  const set<Location> GetValidMoves(int row, int col) const;

  //! @brief Undo the last Move of the game.
  //! @return A pointer to the move undone or NULL if no move was undone.
  //!
  //! Note that the object that the pointer points to must be deleted by the user.
  Move * UndoMove();

  //! @brief Clear the board of all pieces and move history.
  void Clear();

  //! @brief Determine if a player is in check.
  //! @param color The color of the player to test check
  //! @return true if the player is in check. False otherwise.
  bool IsInCheck(Color color) const;

  //! @brief Determine if a player is in checkmate.
  //! @param color The color of the player to test checkmate
  //! @return true if the player is in checkmate. False otherwise.
  bool IsInCheckMate(Color color) const;

  //! @brief Determine if the game is a stale mate.
  //! @return true if the game is in a stale mate.
  bool StaleMate() const;

  const set<Piece *> & GetPieces(Color color) const;

  const Location GetPieceLocation(const Piece * piece) const;

  const Board & GetBoard() const;

  const deque<Move> & GetHistory() const;

private:
  void UpdateGameState(const Move * lastMove);
  void SetCheckAndMate(Color nextTurnColor);
};

#endif /* GAME_H */
